--短连接管理
local incrservicepoolmng = require "incrservicepoolmng"
local filelog = require "filelog"
local skynet = require "skynet"
local timetool = require "timetool"

local service = nil
local ShortTcpMng = {
	connections = {},
	agentpool = nil,
}

--[[
connections 结构
{
		fd = fd,
		ipport = ipport,
		time = timetool.get_time(),
		isclose = false
		agent = agentservice.service
}
]]

function ShortTcpMng.init(callerservice, agentmodule, agentsize, agentincr, netpackmodule)
 	ShortTcpMng.agentpool = incrservicepoolmng:new({}, {service_name=agentmodule, service_size=agentsize, incr=agentincr}, netpackmodule)
	service = callerservice
	skynet.fork(function()
		local now_time
		while true do
			skynet.sleep(40)
			now_time = timetool.get_time()
			for fd, c in pairs(ShortTcpMng.connections) do
				if c.agent == nil then
					if c.time + 5 <= now_time then -- 开发期间，这可以是20，方便调试，正式环境需要尽量设置小
						skynet.pcall(skynet.call, service.gate_service, "lua", "kick", fd)
						c.isclose = true
						filelog.sys_warning("delete zombie connection", fd, c)
					end
				end
			end
		end
	end)
end

function ShortTcpMng.open_socket(fd, ipport)
	local status, result = skynet.pcall(skynet.call, service.gate_service, "lua", "accept", fd)
	
	if not status then
		skynet.pcall(skynet.call, service.gate_service, "lua", "kick", fd)
		return		
	end

	ShortTcpMng.connections[fd] = {
		fd = fd,
		ipport = ipport,
		time = timetool.get_time(),
		isclose = nil,
		agent = nil, -- 这里需要一个到agent的指向，方便可以给agent发消息
	}

	filelog.sys_info("New client from : " ..ipport.." fd:"..fd)
end

function ShortTcpMng.close_socket(fd)
	--如果对应的服务存在通知服务玩家掉线
	local c = ShortTcpMng.connections[fd]
	if c ~= nil then
		if not c.isclose then
			skynet.pcall(skynet.call, service.gate_service, "lua", "kick", fd)		
		else
			filelog.sys_warning("has kick ShortTcpMng.close_socket")
		end
	end

	if c ~= nil and c.agent ~= nil then
		skynet.pcall(skynet.send, c.agent, "lua", "cmd", "close")		
	end

	ShortTcpMng.connections[fd] = nil
end

--表示agent已经退出后的处理
function ShortTcpMng.agentexit(fd)
	local c = ShortTcpMng.connections[fd]
	if c ~= nil then
		skynet.pcall(skynet.call, service.gate_service, "lua", "kick", fd)
		if c.agent ~= nil then
			skynet.pcall(skynet.send, c.agent, "lua", "cmd", "close")
		end
		ShortTcpMng.connections[fd] = nil
	end 
end

function ShortTcpMng.create_session(fd, msgname, msgbody, realip)
 	local result = false
	local status = false	
	-- 从agent池中获取一个agent service
	local agentservice = ShortTcpMng.agentpool:create_service()
	if agentservice == nil then
		filelog.sys_error("ShortTcpMng.create_session not enough agentservice")		
		return false
	end

    if ShortTcpMng.connections[fd] == nil then
		filelog.sys_warning("ShortTcpMng.create_session new connection[fd] == nil", fd)
		skynet.pcall(skynet.send, agentservice.service, "lua", "cmd", "close")
		return false
	end

	if (realip ~= nil) then
		ShortTcpMng.connections[fd].ipport = realip .. ":0"
	end
	
	status, result = skynet.pcall(skynet.call, agentservice.service, "lua", "cmd", "create_session", 
					{ipport=ShortTcpMng.connections[fd].ipport, gate = service.gate_service, client = fd, 
					watchdog = skynet.self(), msgname=msgname, msgbody=msgbody} )
	if (not status) or (not result)then
		filelog.sys_error("ShortTcpMng.create_session agent create_session failed", result)
		skynet.pcall(skynet.kill, agentservice.service) 
		ShortTcpMng.close_socket(fd)
		return false		
	end

    if ShortTcpMng.connections[fd] == nil then
		filelog.sys_warning("ShortTcpMng.create_session new connection[fd] == nil", fd)
		skynet.pcall(skynet.send, agentservice.service, "lua", "cmd", "close")
		return false
	end

	ShortTcpMng.connections[fd].agent = agentservice.service
	return result
end

function ShortTcpMng.clear()
	for fd, _ in pairs(ShortTcpMng.connections) do
		 ShortTcpMng.close_socket(fd)
	end

	if ShortTcpMng.agentpool ~= nil then
		local iter = ShortTcpMng.agentpool:idle_service_iter()
		local service = iter()
		while service do
			skynet.pcall(skynet.send, service, "lua", "cmd", "close")
			service = iter()
		end
	end
end 

return ShortTcpMng